from twisted.internet import defer, reactor
from twisted.spread import pb
from twisted.cred import credentials

from option import Option
import signals
import helpers
import gtk
import gobject
import timer
import pickle
import netMind

class PBFooFactory(pb.PBClientFactory):
	def __init__(self, credentials, data):
		self.foo_credentials = credentials
		self.foo_data = data
		pb.PBClientFactory.__init__(self)

	def clientConnectionFailed(self, connector, reason):
		Option().tabNet.log('Connection failed. Reason : %s' % str(reason))
		pb.PBClientFactory.clientConnectionFailed(self, connector, reason)

	def clientConnectionMade(self, broker):
		Option().tabNet.log('Connected to the server. Authenticating.')
		pb.PBClientFactory.clientConnectionMade(self, broker)
		m = netMind.NetMind()
		d = self.login(self.foo_credentials, m) \
				.addCallback(m.connected, self.foo_data) \
				.addErrback(lambda _: Option().tabNet.log('Authentication failed: %s' % _))

class Net:
	def __init__(self, parent):
		self.parent = parent

		self.tab = parent.xml.get_widget('PageNet')

		self.connectedTo = parent.xml.get_widget('LabConnectedTo')

		self.serverName = parent.xml.get_widget('EntryServerName')
		self.hostName = parent.xml.get_widget('EntryHostname')
		self.user = parent.xml.get_widget('EntryUsername')
		self.password = parent.xml.get_widget('EntryPassword')
		
		self.connectionLog = parent.xml.get_widget('TextConnectionLog')
		#self.connectionLog = parent.xml.get_widget('TreeConnectionLog')
		self.serverList = parent.xml.get_widget('TreeServerList')
		self.servers = {}

		self.userList = parent.xml.get_widget('TreeUserList')
		self.users = []
		self.chatBox = parent.xml.get_widget('TextChat')
		self.chatEntry = parent.xml.get_widget('EntryChat')

		self.butChatSend = parent.xml.get_widget('ButChatSend')
		self.butConnect = parent.xml.get_widget('ButConnect')
		self.butDisconnect = parent.xml.get_widget('ButDisconnect')

		self.eventsTable = parent.xml.get_widget('TableEvents')
		self.eventsInfo = []
		self.eventInfo = parent.xml.get_widget('TextEventInfo')
		self.eventRegister = parent.xml.get_widget('ButEventRegister')
		self.alreadyRegistered = parent.xml.get_widget('LabAlreadyRegistered')

		self.initServerList()
		self.initUserList()
		#self.initConnectionLog()
		self.lastLog = 0
		self.connectionData = None

		parent.xml.signal_autoconnect(self)
	
	def teardown(self):
		# Saving server list
		data = {}
		for server in self.serverList.get_model():
			data[server[0]] = {'host': server[1], 'user': server[2]}

		Option().config.set('net.servers', data)

	def initServerList(self):
		list = gtk.ListStore(str, str, str)
		self.serverList.set_model(list)
		nameCol = gtk.TreeViewColumn('Server')
		hostCol = gtk.TreeViewColumn('Hostname')
		userCol = gtk.TreeViewColumn('Username')

		self.serverList.append_column(nameCol)
		self.serverList.append_column(hostCol)
		self.serverList.append_column(userCol)

		nameCell = gtk.CellRendererText()
		nameCol.pack_start(nameCell, True)
		nameCol.add_attribute(nameCell, 'text',0)

		hostCell = gtk.CellRendererText()
		hostCol.pack_start(hostCell, True)
		hostCol.add_attribute(hostCell, 'text',1)

		userCell = gtk.CellRendererText()
		userCol.pack_start(userCell, True)
		userCol.add_attribute(userCell, 'text',1)

		# Loading data

		servers = Option().config.get('net.servers', [])
		for server in servers:
			list.append((server, servers[server]['host'], servers[server]['user']))


	def initConnectionLog(self):
		list = gtk.ListStore(int,str)
		self.connectionLog.set_model(list)
		idCol = gtk.TreeViewColumn()
		logCol = gtk.TreeViewColumn()

		self.connectionLog.append_column(idCol)
		self.connectionLog.append_column(logCol)

		idCell = gtk.CellRendererText()
		idCol.pack_start(idCell, True)
		idCol.add_attribute(idCell, 'text',0)
		idCol.set_property('visible', False)

		logCell = gtk.CellRendererText()
		logCol.pack_start(logCell, True)
		logCol.add_attribute(logCell, 'text',1)
		logCell.set_property('ypad',0)

		list.set_sort_column_id(0, gtk.SORT_ASCENDING)
		self.lastLog = 0

	def initUserList(self):
		list = gtk.ListStore(str)
		self.userList.set_model(list)
		userCol = gtk.TreeViewColumn()

		self.userList.append_column(userCol)

		userCell = gtk.CellRendererText()
		userCol.pack_start(userCell, True)
		userCol.add_attribute(userCell, 'text',0)

		list.set_sort_column_id(0, gtk.SORT_ASCENDING)

	def populateUserList(self, data = None):
		if data is None:
			data = self.users
		self.users = data

		if self.userList.get_model():
			self.userList.get_model().clear()
		append = self.userList.get_model().append
		for user in data:
			append((user[0],))
	
	def log(self, msg):
		self.lastLog += 1
		#self.connectionLog.get_model().append((self.lastLog, msg))
		buf = self.connectionLog.get_buffer()
		buf.insert(buf.get_end_iter(), msg+'\n')
		self.connectionLog.scroll_to_iter(buf.get_end_iter(), 0)
		self.chat('log', msg)

	def chat(self, user, msg):
		buf = self.chatBox.get_buffer()
		buf.insert(buf.get_end_iter(), '%s: %s\n' %(user, msg))

	def connectionMade(self, obj, data):
		Option().netAvatar = obj
		self.connectionData = data
		self.log('Connected successfully. :-)')
		self.fulfillConnection()
		Option().netAvatar.callRemote('getUsers').addCallback(self.populateUserList)

	def fulfillConnection(self):
		self.connectedTo.set_markup('<b>Connected to %s:%i as %s</b>' % self.connectionData)
		self.connectedTo.set_property('visible',True)
		self.butChatSend.set_sensitive(True)
		self.butConnect.set_sensitive(False)
		self.butDisconnect.set_sensitive(True)

	def fulfillDisconnection(self):
		self.connectedTo.set_property('visible',False)
		self.butChatSend.set_sensitive(False)
		self.butConnect.set_sensitive(True)
		self.butDisconnect.set_sensitive(False)
		if self.userList.get_model():
			self.userList.get_model().clear()

	def connectionLost(self, obj, data = ()):
		del Option().netAvatar
		self.connectionData = None
		self.log('Connection lost!')
		self.fulfillDisconnection()

	def connect(self, host, port, user, password):
		self.log('Attempting connection to %s as %s.' % (host, user))

		Option().netFactory = factory = PBFooFactory(credentials.UsernamePassword(user, password), (host, port, user))
		reactor.connectTCP(str(host), int(port), factory)

	def on_ButDisconnect_clicked(self, widget):
		Option().netFactory.disconnect()

	def on_ButConnect_clicked(self, widget):
		host = self.hostName.get_text()

		if ':' in host:
			host, port = host.rsplit(':', 1)
		else:
			port = 1447

		user = self.user.get_text()
		password = self.password.get_text()

		self.connect(host, port, user, password)
		pass
		

	def on_ButChatSend_clicked(self, widget):
		if self.connectionData and Option().netAvatar:
			Option().netAvatar.callRemote('chat',self.chatEntry.get_text())
			self.chatEntry.set_text('')

	def on_EntryChat_key_release_event(self, widget, event):
		if event.keyval == 65293 and widget.get_text():
			self.on_ButChatSend_clicked(widget)
	
	def on_TreeServerList_row_activated(self, widget, path, foo):
		iter = widget.get_model().get_iter(path)

		data = widget.get_model()[iter]

		self.serverName.set_text(str(data[0]))
		self.hostName.set_text(str(data[1]))
		self.user.set_text(str(data[2]))
		self.password.set_text('')

	def on_ButServerRemove_clicked(self, widget):
		path, foo = self.serverList.get_cursor()
		if path:
			iter = self.serverList.get_model().remove(self.serverList.get_model().get_iter(path))

	def on_ButServerAdd_clicked(self, widget):
		self.serverList.get_model().append((self.serverName.get_text(), self.hostName.get_text(), self.user.get_text()))

	def on_ButEventDetails_clicked(self, widget, event, index):
		pass

	def populateEventsTable(self, data):
		self.eventsTable.foreach(lambda x,y: x.remove(y), self.eventsTable)
		self.eventsTable.resize(len(data), 3)
		row = -1
		for event in data:
			row +=1
			self.eventsTable.attach(gtk.Label(event[0]), 0, 1, row, row+1, gtk.FILL, gtk.FILL)
			self.eventsTable.attach(gtk.Label('<b>(*)</b>' if event[3] else  ''), 1, 2, row, row+1, gtk.FILL, gtk.FILL)
			but = gtk.Button('Details')
			but.connect('clicked', self.on_ButEventDetails_clicked, event[0], row)
			self.eventsTable.attach(but, 2, 3, row, row+1, gtk.FILL, gtk.FILL)
		
		self.eventsInfo = data
		self.eventsTable.show_all()
	
	def recreateEventsTable(self):
		assert Option().netAvatar, 'Not connected.'

		Option().netAvatar.callRemote('getEventsInfo').addCallback(self.populateEventsTable)

	def on_NtbkNet_switch_page(self, widget, foo, page):
		if Option().netAvatar:
			if page == 3:
				self.recreateEventsTable()
			
